home *** CD-ROM | disk | FTP | other *** search
- /*
- * State machine abstraction.
- * The idea is to keep as much of the hookup dialog
- * as possible in a text file, so that hookup protocols
- * are easy to change here or in other apps.
- * It has grown a few warts.
- *
- * M. J. Hawley
- * mike@media-lab.mit.edu
- * Copyright (c) November 1991, MIT Media Laboratory.
- */
-
- extern strlen(), Command(), message(), Put(), Flush(), logout();
- extern strcpy(), pgets(), strcmp();
- extern char *index(), *rindex();
-
- void setState();
-
- typedef enum { Plain, Pattern, Status, Goto, FlushS, Pause, CmdS } SType;
-
- typedef struct String {
- char *s;
- struct String *next;
- } String;
-
- typedef struct {
- int type;
- char *name;
- char *first, *last, *label;
- String *l;
- } State;
-
- #include "util.h"
-
- SType lastType = Plain;
-
- char *getStr(s,t) char *s, *t; {
- char end = ' ';
-
- *t = '\0';
- s = skipsp(s);
- lastType = Plain;
- switch (*s){
- Case '/': lastType = Pattern;
- Case '+': lastType = Status; s++;
- Case '!': lastType = CmdS; s++;
- Case ',': lastType = FlushS; s++;
- Case '=': lastType = Goto; s = skipsp(s+2);
- }
-
- if (*s=='/' || *s == '"') end = *s++;
- while (*s && !(*s == end || (end==' ' && *s == '\t'))){
- *t = *s++;
- if (*t == '\\') switch (*s){
- Case 'n': *t = '\n'; s++;
- Case 't': *t = '\t'; s++;
- Case 'b': *t = '\b'; s++;
- Default : *t = *s; s++;
- }
- t++;
- }
- *t = '\0';
- if (*s && *s != ' ' && *s != '\t') ++s;
- if (*s) s = skipsp(s);
- return s;
- }
-
- State *
- newState(s) char *s; {
- State *S = Alloc(State);
- S->name = save(s);
- return S;
- }
-
- String *
- addStr(s,t) String *s; char *t; {
- String *start = s, *n = Alloc(String);
- char *p;
-
- p = n->s = save(t);
- if (*p=='/' && (p = index(p+1,'/'))){
- while (p[-1]=='\\') p = index(p+1,'/');
- if (p) *p = '\0';
- }
-
- if (!s) return n;
- while (s->next) s = s->next;
- s->next = n;
- return start;
- }
-
- void
- addString(S,s) State *S; char *s; {
- stripnl(s=skipsp(s));
- S->l = addStr(S->l,s);
- }
-
- #define MaxS 256
- static State *ST[MaxS];
- static int NS = 0;
-
- void
- readState(f) FILE *f; {
- char s[1024], n[1024];
- State *S = (State *)0;
- while (fgets(s,sizeof s,f)){
- stripcomment(s);
- if (blank(s)) continue;
- if (match(s,"[a-zA-Z]*:")){
- sscanf(s,"%[^:]",n);
- S = newState(n);
- ST[NS++] = S;
- } else
- if (S){
- addString(S,s);
- }
- }
- }
-
- State*
- state(s) char *s; {
- int i;
- s = skipsp(s);
- for (i=0;i<NS;i++)
- if (strcmp(s,ST[i]->name)==0) return ST[i];
- return (State *)0;
- }
-
- char *str(s) char *s; { return s? s : ""; }
-
- void
- printState(s) State *s; {
- if (!s) printf("huh?\n"); else
- printf("%s: %s %s %s\n",s->name,str(s->first),str(s->last),str(s->label));
- }
-
- void
- ReadState(s) char *s; {
- FILE *f;
- if (!NS){
- f = fopen(s,"r");
- if (f) readState(f), fclose(f);
- }
- setState("Attach");
- }
-
- State *curState = (State *)0;
-
- void
- setState(s) char *s; {
- curState = state(s);
- if (strcmp(s,"Detach")==0) logout();
- if (strcmp(s,"Ready")==0) ready();
- }
-
- void
- execute(s) char *s; {
- char t[1024];
-
- if (s[0]=='/') s += strlen(s)+1;
- while ((s=getStr(s,t)) && *t) switch (lastType){
- Case CmdS: Command(t);
- Case Status : message(t);
- Case Plain : if (!state(t)) Put("%s",t);
- Case FlushS : Flush(t);
- Case Goto : setState(t);
- }
- }
-
- void
- execState(s,t) State *s; char *t; {
- String *l;
- if (!s) s = curState;
- if (!s || !s->l) return;
- for (l=s->l; l; l=l->next){
- if (l->s[0]!='/') execute(l->s);
- else
- if (l->s[0]=='/' && *t && match(t,l->s+1)) execute(l->s);
- }
- }
-
- void
- runState(s) char *s; {
- execState(curState,s);
- }
-
- #define FAILED -1
- #define LIST 1
- #define LISTA 2
- #define ITEM 3
-
- int LastItem = 0;
- int MoreItems=0;
-
- #define MaxItems 10000
- typedef struct {
- int n;
- char s[128];
- } Item;
- Item I[MaxItems];
- int NI=0;
-
- resetItems(){ NI=0; }
-
- char *
- skipdigit(s) char *s; { while (isdigit(*s) && *s) ++s; return skipsp(s); }
-
- copynl(t,s) char *t, *s; {
- while ((*t = *s) && *t != '\n')
- t++, s++;
- *t = '\0';
- if (*s == '\n') ++s;
- return s;
- }
-
- addItemList(s) char *s; {
- char t[256];
- int date, numtitles;
- char author[80], title[80];
- char *pt = " ";
-
- s = skipsp(s);
- if(LastItem==LIST){ // # titles Authors...
- while(*s){
- I[NI].n = atoi(s); s = skipdigit(s);
- numtitles = atoi(s); s = skipdigit(s);
- s = copynl(t,s);
- sprintf(I[NI].s,"%4d %s",numtitles,t);
- NI++;
- }
- } else { // # Auth[22] title date
- while (*s){
- I[NI].n = atoi(s); s = skipdigit(s);
- *title = *author = '\0';
- s = copynl(title,s);
- if (strlen(title)<=22)
- s = copynl(author,s);
- date = atoi(s); s = skipdigit(s);
- if (*author) sprintf(I[NI].s," %s -- %s [%d]",title,author,date);
- else sprintf(I[NI].s," %s -- %s [%d]",pt,title,date);
- NI++;
- }
- }
- message("found %d.",NI);
- }
-
- char *
- nthItem(n){
- return n<NI? I[n].s : "";
- }
-
- nthItemIndex(n){
- return n<NI? I[n].n : 0;
- }
-
- cleanHighlight(t) char *t; {
- char *p = t;
- if (*p == 27) ++p;
- if (*p == '[' && p[1] == '1' && p[2] == 'm')
- strcpy(t,p+3);
- }
-
- int MustReload = 0;
-
- char *
- getReport(buf, reload) char *buf; {
- char *p = buf;
- char t[1024], c;
- int n = 1, More = 3, more=0;
- int flush=0;
- MustReload = reload;
- message("found 0");
- LastItem = 0;
- *p++ = '\n';
- MORE:
- flush=more=0;
- while ((c=pgetc()) && c != '>'){
- t[0] = c; pgetsx(t+1);
- cleanHighlight(t);
- cleanEsc(t); strcpy(t,skipsp(t));
- if (blank(t) || (t[0]=='n' && t[1]=='\n')) continue;
- if (Verbose) printf("+%s",t);
- if (strindex(t,"Your search:")) continue; else
- if (strindex(t,"Your search for")) flush++, LastItem=FAILED; else
- if (strindex(t,"When searching for")) flush++, LastItem=FAILED; else
- if (strindex(t,"Type of Material:")) LastItem = ITEM; else
- if (strindex(t,"# titles ------")) LastItem = LIST; else
- if (strindex(t,"# --------Author-------- ")) LastItem = LISTA; else
- if (strncmp(t,"LINE",4)==0){
- if (Verbose) printf("++LINE\n");
- LastItem = LIST;
- continue;
- }
- if (t[1]=='=') continue;
- if (strncmp(t,"No more records",14)==0) More=more=0, flush++;
- if (strncmp(t,"# ",4)==0) continue;
- if (strncmp(t,"----",7)==0) flush++;
- if (strncmp(t,"Enter:",6)==0) flush++;
- if (strncmp(t,"(More)",6)==0) more++, More--, flush++;
- if (strindex(t,"HINTS:")) flush++;
- if (strncmp(t,"Line #",6)==0) flush++;
- if (flush) continue;
-
- if (LastItem == ITEM && strncmp(t,"(Record ",8)==0) continue;
- if (LastItem == ITEM && (!index(t,':') || index(t,':')[-1] ==' ')){
- --p;
- if (*p != ' ') *p++ = ' ';
- }
- strcpy(p,t); p += strlen(p);
- }
- pgetc(); // read the other '>'
- if (more && (More > 0 || LastItem == ITEM)){
- Put("n\r");
- goto MORE;
- }
- if (LastItem == ITEM){
- Put("b\r"); pgets(t);
- }
- MoreItems = more;
- if (LastItem != ITEM) enableMore(MoreItems);
- message("found %d",LastItem==ITEM? 1 : n-1);
- *p = '\0';
-
- if (LastItem != ITEM) addItemList(buf);
- return buf;
- }
-
- getItem(buf,n) char *buf; {
- char t[256];
- extern reload();
- Put("%d\r",n); pgets(t);
- resetItems();
- getReport(buf,0);
- if (LastItem == ITEM) return 1;
- MustReload = 1;
- DPSAddTimedEntry(1.0,reload,0,10);
- return 0;
- }
-